/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "gundrak.h"

enum Spells
{
    SPELL_MOJO_PUDDLE					= 55627,
    SPELL_MOJO_WAVE						= 55626,
    SPELL_FREEZE_ANIM					= 52656,
    SPELL_MIGHTY_BLOW					= 54719,

	SPELL_ELEMENTAL_SPAWN_EFFECT		= 54888,
    SPELL_EMERGE						= 54850,
    SPELL_EMERGE_SUMMON					= 54851,
	SPELL_MOJO_VOLLEY					= 54849,

	SPELL_SURGE_VISUAL					= 54827,
    SPELL_SURGE							= 54801,
	SPELL_SURGE_DAMAGE					= 54819,

	SPELL_FACE_ME						= 54991,
    SPELL_MERGE							= 54878,
};

enum Misc
{
	NPC_LIVING_MOJO						= 29830,
	NPC_DRAKKARI_ELEMENTAL				= 29573,

	ACTION_MERGE						= 1,
	ACTION_INFORM						= 2,

	POINT_MERGE							= 1,
	SAY_SURGE							= 0,
	EMOTE_ALTAR							= 1,

	EVENT_COLOSSUS_MIGHTY_BLOW			= 1,
	EVENT_COLOSSUS_HEALTH_1				= 2,
	EVENT_COLOSSUS_HEALTH_2				= 3,
	EVENT_COLOSSUS_START_FIGHT			= 4,

	EVENT_ELEMENTAL_HEALTH				= 10,
	EVENT_ELEMENTAL_SURGE				= 11,
	EVENT_ELEMENTAL_VOLLEY				= 12,

	EVENT_MOJO_MOJO_WAVE				= 20,
	EVENT_MOJO_MOJO_PUDDLE				= 21,
};

static Position mojoPosition[] =
{
	{1663.1f, 743.6f, 143.1f},
	{1669.97f, 753.7f, 143.1f},
	{1680.7f, 750.7f, 143.1f},
	{1680.7f, 737.1f, 143.1f},
	{1670.4f, 733.5f, 143.1f}
};

class RestoreFight : public BasicEvent
{
    public:
        RestoreFight(Creature* owner) : _owner(owner) { }

        bool Execute(uint64 /*execTime*/, uint32 /*diff*/)
        {
			_owner->SetReactState(REACT_AGGRESSIVE);
			_owner->SetInCombatWithZone();
            return true;
        }

    private:
        Creature* _owner;
};

class boss_drakkari_colossus : public CreatureScript
{
	public:
		boss_drakkari_colossus() : CreatureScript("boss_drakkari_colossus") { }

		CreatureAI* GetAI(Creature* creature) const
		{
			return new boss_drakkari_colossusAI (creature);
		}
		struct boss_drakkari_colossusAI : public BossAI
		{
			boss_drakkari_colossusAI(Creature* creature) : BossAI(creature, DATA_DRAKKARI_COLOSSUS)
			{
			}

			void MoveInLineOfSight(Unit* who)
			{
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_INFORM)
				{
					me->SetInCombatWithZone();
					summons.DoAction(ACTION_MERGE);
					events.ScheduleEvent(EVENT_COLOSSUS_START_FIGHT, 3500);
				}
			}

			void Reset()
			{
				BossAI::Reset();
				for (uint8 i = 0; i < 5; i++)
					me->SummonCreature(NPC_LIVING_MOJO, mojoPosition[i].GetPositionX(), mojoPosition[i].GetPositionY(), mojoPosition[i].GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 0);

				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
			}

			void InitializeAI()
			{
				BossAI::InitializeAI();
				me->CastSpell(me, SPELL_FREEZE_ANIM, true);
			}

			void JustReachedHome()
			{
				BossAI::JustReachedHome();
				me->CastSpell(me, SPELL_FREEZE_ANIM, true);
			}
			
			void EnterCombat(Unit* who)
			{
				BossAI::EnterCombat(who);
				events.ScheduleEvent(EVENT_COLOSSUS_MIGHTY_BLOW, 10000);
				events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_1, 1000);
				events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_2, 1000);
			}

			void JustSummoned(Creature* summon) 
			{
				if (summon->GetEntry() == NPC_DRAKKARI_ELEMENTAL)
				{
					summon->SetRegeneratingHealth(false);
					summon->SetReactState(REACT_PASSIVE);
					summon->m_Events.AddEvent(new RestoreFight(summon), summon->m_Events.CalculateTime(3000));
					if (events.GetNextEventTime(EVENT_COLOSSUS_HEALTH_2) == 0)
					{
						summon->SetHealth(summon->GetMaxHealth()/2);
						summon->LowerPlayerDamageReq(summon->GetMaxHealth()/2);
						summon->AI()->DoAction(ACTION_INFORM);
					}
				}

				summons.Summon(summon);
			}

			void SummonedCreatureDies(Creature* summon, Unit*)
			{
				summons.Despawn(summon);
				if (summon->GetEntry() == NPC_DRAKKARI_ELEMENTAL)
					Unit::Kill(me, me);
			}

			void SummonedCreatureDespawn(Creature* summon)
			{
				summons.Despawn(summon);
				if (summon->GetEntry() == NPC_DRAKKARI_ELEMENTAL)
				{
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
					me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
					if (me->GetVictim())
						me->GetMotionMaster()->MoveChase(me->GetVictim());
				}
			}

			void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask)
			{
				if (damage >= me->GetHealth())
					damage = 0;
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
					return;

				events.Update(diff);
				switch (events.ExecuteEvent())
				{
					case EVENT_COLOSSUS_START_FIGHT:
						me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
						me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
						break;
					case EVENT_COLOSSUS_MIGHTY_BLOW:
						me->CastSpell(me->GetVictim(), SPELL_MIGHTY_BLOW, false);
						events.ScheduleEvent(EVENT_COLOSSUS_MIGHTY_BLOW, 10000);
						break;
					case EVENT_COLOSSUS_HEALTH_1:
						if (me->HealthBelowPct(51))
						{
							me->CastSpell(me, SPELL_EMERGE, false);
							me->CastSpell(me, SPELL_EMERGE_SUMMON, true);
							me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
							me->GetMotionMaster()->Clear();
							break;
						}
						events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_1, 1000);
						break;
					case EVENT_COLOSSUS_HEALTH_2:
						if (me->HealthBelowPct(21))
						{
							me->CastSpell(me, SPELL_EMERGE, false);
							me->CastSpell(me, SPELL_EMERGE_SUMMON, true);
							me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
							me->GetMotionMaster()->Clear();
							break;
						}
						events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_2, 1000);
						break;
				}

				DoMeleeAttackIfReady(); 
			}
		};
};

class boss_drakkari_elemental : public CreatureScript
{
	public:
		boss_drakkari_elemental() : CreatureScript("boss_drakkari_elemental") { }

		CreatureAI* GetAI(Creature* pCreature) const
		{
			return new boss_drakkari_elementalAI (pCreature);
		}

		struct boss_drakkari_elementalAI : public ScriptedAI
		{
			boss_drakkari_elementalAI(Creature* pCreature) : ScriptedAI(pCreature)
			{
				events.ScheduleEvent(EVENT_ELEMENTAL_HEALTH, 1000);
				events.ScheduleEvent(EVENT_ELEMENTAL_SURGE, 7000);
				events.ScheduleEvent(EVENT_ELEMENTAL_VOLLEY, 0);
			}

			EventMap events;

			void DoAction(int32 param)
			{
				if (param == ACTION_INFORM)
					events.CancelEvent(EVENT_ELEMENTAL_HEALTH);
			}

			void Reset()
			{
				me->CastSpell(me, SPELL_ELEMENTAL_SPAWN_EFFECT, false);
			}

			void JustDied(Unit*)
			{
				Talk(EMOTE_ALTAR);
			}

			void EnterCombat(Unit*)
			{
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_ELEMENTAL_HEALTH:
						if (me->HealthBelowPct(51))
						{
							me->CastSpell(me, SPELL_FACE_ME, true);
							me->CastSpell(me, SPELL_SURGE_VISUAL, true);
							me->CastSpell(me, SPELL_MERGE, false);
							me->DespawnOrUnsummon(2000);
							events.Reset();
							break;
						}
						events.ScheduleEvent(EVENT_ELEMENTAL_HEALTH, 1000);
						break;
					case EVENT_ELEMENTAL_SURGE:
						Talk(SAY_SURGE);
						me->CastSpell(me, SPELL_SURGE_VISUAL, true);
						me->CastSpell(me->GetVictim(), SPELL_SURGE, false);
						events.ScheduleEvent(EVENT_ELEMENTAL_SURGE, 15000);
						break;
					case EVENT_ELEMENTAL_VOLLEY:
						me->CastSpell(me, SPELL_MOJO_VOLLEY, true);
						break;
				}


				DoMeleeAttackIfReady();
			}
		};
};

class npc_living_mojo : public CreatureScript
{
	public:
		npc_living_mojo() : CreatureScript("npc_living_mojo") { }

		CreatureAI* GetAI(Creature* pCreature) const
		{
			return new npc_living_mojoAI (pCreature);
		}

		struct npc_living_mojoAI : public ScriptedAI
		{
			npc_living_mojoAI(Creature* pCreature) : ScriptedAI(pCreature)
			{
			}

			EventMap events;

			void Reset()
			{
				events.Reset();
				events.ScheduleEvent(EVENT_MOJO_MOJO_PUDDLE, 13000);
				events.ScheduleEvent(EVENT_MOJO_MOJO_WAVE, 15000);
			}

			void MoveInLineOfSight(Unit* who)
			{
				if (me->ToTempSummon())
					return;

				ScriptedAI::MoveInLineOfSight(who);
			}

			void AttackStart(Unit* who)
			{
				if (me->ToTempSummon())
				{
					if (who->GetTypeId() == TYPEID_PLAYER || IS_PLAYER_GUID(who->GetOwnerGUID()))
						if (Unit* summoner = me->ToTempSummon()->GetSummoner())
							summoner->GetAI()->DoAction(ACTION_INFORM);
					return;
				}

				ScriptedAI::AttackStart(who);
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_MERGE)
				{
					me->SetReactState(REACT_PASSIVE);
					me->GetMotionMaster()->MoveCharge(1672.96f, 743.488f, 143.338f, 7.0f, POINT_MERGE);
					me->DespawnOrUnsummon(1200);
				}
			}

			void UpdateAI(uint32 diff)
			{
				if (me->ToTempSummon() || !UpdateVictim())
					return;
				
				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_MOJO_MOJO_PUDDLE:
					{
						me->CastSpell(me, SPELL_MOJO_PUDDLE, false);
						events.ScheduleEvent(EVENT_MOJO_MOJO_PUDDLE, 13000);
						break;
					}
					case EVENT_MOJO_MOJO_WAVE:
					{
						me->CastSpell(me->GetVictim(), SPELL_MOJO_WAVE, false);
						events.ScheduleEvent(EVENT_MOJO_MOJO_WAVE, 15000);
						break;
					}
				}

				DoMeleeAttackIfReady();
			}
		};
};

class spell_drakkari_colossus_emerge : public SpellScriptLoader
{
    public:
        spell_drakkari_colossus_emerge() : SpellScriptLoader("spell_drakkari_colossus_emerge") { }

        class spell_drakkari_colossus_emerge_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_drakkari_colossus_emerge_SpellScript);

            void HandleDummy(SpellEffIndex /*effIndex*/)
            {
                GetCaster()->CastSpell(GetCaster(), SPELL_FREEZE_ANIM, true);
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_drakkari_colossus_emerge_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_drakkari_colossus_emerge_SpellScript();
        }
};

class spell_drakkari_colossus_surge : public SpellScriptLoader
{
    public:
        spell_drakkari_colossus_surge() : SpellScriptLoader("spell_drakkari_colossus_surge") { }

        class spell_drakkari_colossus_surge_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_drakkari_colossus_surge_SpellScript);

            void HandleDummy(SpellEffIndex /*effIndex*/)
            {
                if (Unit* target = GetHitUnit())
                    GetCaster()->CastSpell(target, SPELL_SURGE_DAMAGE, true);
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_drakkari_colossus_surge_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_drakkari_colossus_surge_SpellScript();
        }
};

class spell_drakkari_colossus_face_me : public SpellScriptLoader
{
    public:
        spell_drakkari_colossus_face_me() : SpellScriptLoader("spell_drakkari_colossus_face_me") { }

        class spell_drakkari_colossus_face_me_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_drakkari_colossus_face_me_SpellScript);

            void HandleScriptEffect(SpellEffIndex /*effIndex*/)
            {
                if (Unit* target = GetHitUnit())
				{
					GetCaster()->SetInFront(target);
                    GetCaster()->SetFacingTo(GetCaster()->GetAngle(target));
				}
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_drakkari_colossus_face_me_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_drakkari_colossus_face_me_SpellScript();
        }
};

void AddSC_boss_drakkari_colossus()
{
    new boss_drakkari_colossus();
    new boss_drakkari_elemental();
    new npc_living_mojo();
	new spell_drakkari_colossus_emerge();
	new spell_drakkari_colossus_surge();
	new spell_drakkari_colossus_face_me();
}
